import 'dart:math';

import 'package:memo/state/model/work_record.dart';
import 'package:sqflite/sqflite.dart';
import 'package:uuid/uuid.dart';

enum TodoType { success, error, waring }

class Todo {
  String id;
  String note;
  DateTime time;
  TodoType type;
  String workRecordId;

  Todo({this.id, this.note, this.time, this.type, this.workRecordId}) {
    this.id = this.id == null ? Uuid().v4().replaceAll("-", "") : this.id;
    this.time = this.time == null ? DateTime.now() : this.time;
    this.type = this.type == null
        ? TodoType.values[Random().nextInt(TodoType.values.length)]
        : this.type;
  }

  static Todo fromMap(Map<String, dynamic> map) {
    return Todo(
        id: map["id"],
        note: map["note"],
        time: DateTime.fromMillisecondsSinceEpoch(map["time"]),
        type: _convertNumToType(map["type"]),
        workRecordId: map["workRecordId"]);
  }

  static List<Todo> fromMaps(List<Map<String, dynamic>> list) {
    return list.map((m) => fromMap(m)).toList();
  }

  @override
  String toString() {
    return 'Todo{id: $id, note: $note, time: $time, type: $type}';
  }
}

TodoType _convertNumToType(int type) {
  return type == 0
      ? TodoType.success
      : (type == 1 ? TodoType.waring : TodoType.error);
}

const todoTableName = "todo_list";

const todoSQL = """CREATE TABLE $todoTableName (
    id CHAR(32) PRIMARY KEY NOT NULL,
    note VARCHAR(100) NOT NULL,
    time BIGINT NOT NULL,
    type SMALLINT NOT NULL,
    workRecordId CHAR(32) NOT NULL
  )""";

const insertTodoSQL = """
insert into $todoTableName (id, note, time, type, workRecordId) values (?,?,?,?,?)
""";

const updateTodoSQL = """
update $todoTableName set time = ?, note = ?, type = ? where id = ?
""";

const deleteTodoSQL = """
delete from $todoTableName where id = ?
""";

const queryTodoByIdSQL = """
select id, note, time, type, workRecordId from $todoTableName where id = ? limit 1
""";

const queryTodoByWorkRecordIdSQL = """
select id, note, time, type, workRecordId from $todoTableName where workRecordId = ? 
order by time asc limit ?,?
""";

Future<void> insertTodo(Database db, Todo todo) async {
  await db.rawInsert(insertTodoSQL, [
    todo.id,
    todo.note,
    todo.time.millisecondsSinceEpoch,
    _convertTypeToNum(todo.type),
    todo.workRecordId
  ]);
}

Future<void> updateTodoById(Database db, Todo todo) async {
  await db.rawUpdate(updateTodoSQL, [
    todo.time.millisecondsSinceEpoch ~/ 1000,
    todo.note,
    _convertTypeToNum(todo.type),
    todo.id
  ]);
}

Future<void> deleteTodo(Database db, String todoId) async {
  await db.rawDelete(deleteTodoSQL, [todoId]);
}

Future<Todo> queryTodoById(Database db, String todoId) async {
  final todo = await db.rawQuery(queryTodoByIdSQL, [todoId]);
  return todo.isNotEmpty ? Todo.fromMap(todo[0]) : null;
}

Future<List<Todo>> queryTodoByWorkRecord(Database db, String workRecord,
    {int start = 0, int len = 8}) async {
  final list =
      await db.rawQuery(queryTodoByWorkRecordIdSQL, [workRecord, start, len]);
  print("queryTodo: ${list.length}");
  return Todo.fromMaps(list);
}

Future<List<Todo>> queryTodoByTime(
    Database db, DateTime startTime, DateTime endTime) async {
  final workRecord = await queryWorkRecordByDay(db, startTime, endTime);
  print("startTime: ${startTime.toString()}, endTime: ${endTime.toString()}, workRecord: ${workRecord == null}");
  if (workRecord == null) return [];
  return await queryTodoByWorkRecord(db, workRecord.id, len: 50);
}

int _convertTypeToNum(TodoType type) {
  return TodoType.success == type ? 0 : (TodoType.waring == type ? 1 : 2);
}

void main() {
  final list = List.generate(
      5, (index) => Todo(id: index.toString(), note: "Hello $index"));

  list[3] = Todo(id: "3", note: "333");
  list.forEach((t) => print(t));
}
